﻿/*
 * Registers and Synchronize the Modules and Modules Nodes
 * "sitebuilder Project" 2009
 * Email:imlarrybs@gmail.com
*/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.IO;
using System.Diagnostics;
using xtra.domain.Subsonic3;
using SubSonic.Repository;

namespace sb.tools {
    class Program {
        public class DistinctNodeHolders : IEqualityComparer<Match> {
            public bool Equals(Match x, Match y) {
                return x.Groups["uid"].Value == y.Groups["uid"].Value;
            }
            public int GetHashCode(Match obj) {
                return obj.Groups["uid"].Value.GetHashCode();
            }
        }

        private static List<Plugin> plugins;
        static IRepository repo = new SimpleRepository();

        static string uid = null;
        static string uri = null;

        private static Regex rexNode = new Regex(@"<sb:ModuleNode.+?Title=""(?<title>[\s\w]+?)"".+?ID=""(?<uid>\w+?)""", RegexOptions.Singleline);
        private const string path = @"C:\@wrork\ASP.NET.Projects\Projects\sitebuilder\xtraclub\xtra.website\plugin\)";
        private static Regex rexModuleUri = new Regex(@"\\plugin\\(?<path>[\w\\]+?)\\p.ascx", RegexOptions.IgnoreCase | RegexOptions.Singleline);

        static void Main(string[] args) {
            try {
                Start();
            } catch (Exception ex) {
                throw ex;
            }
        }
        private static void Start() {
            List<string> pluginFlolder = new List<string>(Directory.GetDirectories(Path.GetDirectoryName(path), "*", SearchOption.AllDirectories));

            // List of all the registerd Modules
            plugins = (from a in repo.All<Plugin>()
                       //where a.URI != null
                       select a).ToList();

            //Sync PageModule Register
            pluginFlolder.ForEach(item =>
            {
                DirectoryInfo dir = new DirectoryInfo(item);

                // Take only p.ascx files
                FileInfo[] files = dir.GetFiles("p.ascx");
                if (files.Length > 0) {
                    FileInfo file = files[0];
                    
                    // Gets the file's creation date and hashes it 
                    FileInfo[] uidFile = dir.GetFiles("*.uid");
                    if (uidFile.Length > 0) {
                        uid = uidFile[0].Name.Replace(".uid",""); //GenericRoutines.GetMd5Sum(file.CreationTimeUtc.ToString());
                    } else {
                        throw new Exception("Nof found UID File");
                    }

                    //Figures out the module's URI
                    Match match = rexModuleUri.Match(file.FullName);
                    if (match.Success) {
                        uri = match.Groups["path"].Value;
                    } else {
                        throw new Exception("Cannot figure out the module's URI");
                    }

                    Plugin found = plugins.Find(m =>
                    {
                        return m.UID == uid || m.URI == uri;
                    });

                    UpdateModules(file, found);

                    if (found != null) {
                        UpdateNodes(file, found);
                    }
                }
            });

            repo.UpdateMany(plugins);
        }

        private static void UpdateNodes(FileInfo file, Plugin module) {
            List<Plugin> nodes = plugins.FindAll(item =>
            {
                return item.ParentId == module.Id;
            });

            List<Match> nodeHolders = GetNodeHolders(file);
            nodeHolders.ForEach(delegate(Match match) {
                string title = match.Groups["title"].Value;
                string uid = match.Groups["uid"].Value;

                Plugin node = null;
                if (nodes.Count > 0) {
                    node = nodes.Find(n =>
                    {
                        return n.UID == uid || n.Title == title.ToLower();
                    });
                }

                if (node == null) {
                    Plugin newNode = new Plugin();
                    newNode.UID = uid;
                    newNode.Title = title.ToLower();
                    newNode.ParentId = module.Id;
                    repo.Add(newNode);
                } else {
                    node.UID = uid;
                    node.Title = title.ToLower();
                }
            });

            repo.UpdateMany(nodes);

            //UnregisterRemoved(nodes, nodeHolders);
        }

        private static void UnregisterRemoved(List<Plugin> nodes, List<Match> nodeHolders) {
            // Unregisters the removed from markup
            //nodes.RemoveAll(item => {
            //    return item.PageModulePageNodeRecords.Count != 0 || null != nodeHolders.Find(delegate(Match match) {
            //        return match.Groups["uid"].Value == item.UID;
            //    });
            //});

            //if (nodes.Count > 0) {
            //    while (nodes.Count > 0) {
            //        nodes.RemoveAt(0);
            //    }
            //    repo.UpdateMany(nodes);
            //    repo.DeleteMany(nodes);
            //}
        }

        private static void UpdateModules(FileInfo file, Plugin module) {
            // If the module is not yet registerd - do it
            if (module == null) {
                repo.Add(new Plugin()
                {
                    UID = uid,
                    URI = uri
                });
            } else {
                module.UID = uid;
                module.URI = uri;
            }
        }

        #region Helpers
        private static List<Match> GetNodeHolders(FileInfo file) {
            MatchCollection m = rexNode.Matches(File.ReadAllText(file.FullName));
            Match[] array = new Match[m.Count];

            m.CopyTo(array, 0);

            List<Match> list = new List<Match>(array);
            var distinct = list.Distinct(new DistinctNodeHolders());
            if (distinct.Count() != list.Count) {
                throw new Exception("Found duplicate UID on the file:" + file);
            }
            return list;
        }
        #endregion
    }
}
